#include <main.h>

typedef enum{
    DMA_BYTE1=0,   //2^0 1bytes=8bit
    DMA_BYTE2=1,   //2^1 2bytes=16bit
    DMA_BYTE4=2,   //2^2 4bytes=32bit
    DMA_BYTE16=3,  //2^3 16bytes=64bit
} DMA_BYTEn;
/******************************************************************************
*函  数：DMA_MEM2MEM_Init
*功　能：DMA 内存到内存初始化
*参  数：
*				DMA_CHn   : 通道号（DMA_CH0 ~ DMA_CH15）
*				SADDR     : 源地址( (void * )&PTx_BYTEn_IN 或 (void * )&PTx_WORDn_IN )
*				DADDR     : 目的地址
*       ptxn      : 触发端口
*       DMA_BYTEn : 每次DMA传输字节数
*				count     : 一个主循环传输字节数
*返回值：无
*备  注：无
*******************************************************************************/
void DMA_MEM2MEM_Init(DMA_CHn CHn, void *SADDR, void *DADDR, DMA_BYTEn byten, u32 count)
{  
  /* 开启DMA时钟 */
  SIM->PLATCGC  |= SIM_PLATCGC_CGCDMA(1);
  if(PCC->PCCn[PCC_DMAMUX_INDEX] != PCC_PCCn_CGC_MASK)
     PCC->PCCn[PCC_DMAMUX_INDEX]  = PCC_PCCn_CGC_MASK;          // CGC=1: Clock enabled for DMA  
  
  uint8_t BYTEs = (byten == DMA_BYTE1?1:(byten == DMA_BYTE2?2:(byten == DMA_BYTE4?4:16) ) ); //计算传输字节数
  
  DMA->TCD[CHn].CSR &= 0xFFFFFFFF ^ DMA_TCD_CSR_DONE_MASK;  	    // Clear Channel Done flag
  
  /* 配置DMA通道的传输控制块 TCD ( Transfer Control Descriptor ) */
  DMA->TCD[CHn].SADDR =  (uint32_t)SADDR;                            //设置源地址
  DMA->TCD[CHn].DADDR =  (uint32_t)DADDR;                            //设置目的地址
  DMA->TCD[CHn].SOFF  =  BYTEs;                                      //设置源地址偏移 = 0x0, 即不变
  DMA->TCD[CHn].DOFF  =  BYTEs;                                      //每次传输后，目的地址加 BYTEs
  
  DMA->TCD[CHn].ATTR  = DMA_TCD_ATTR_SMOD(0)                    //源地址模数禁止  Source address modulo feature is disabled
                      | DMA_TCD_ATTR_SSIZE(byten)               //源数据位宽：DMA_BYTEn  。    SSIZE = 0 -> 8-bit ，SSIZE = 1 -> 16-bit ，SSIZE = 2 -> 32-bit ，SSIZE = 4 -> 16-byte
                      | DMA_TCD_ATTR_DMOD(0)                    //目标地址模数禁止
                      | DMA_TCD_ATTR_DSIZE(byten);              //目标数据位宽：DMA_BYTEn  。  设置参考  SSIZE
  
  DMA->TCD[CHn].CITER.ELINKNO = DMA_TCD_CITER_ELINKNO_CITER(1)       //当前主循环次数
                         | DMA_TCD_CITER_ELINKNO_ELINK(0);  	// The channel-to-channel linking is disabled
  
  DMA->TCD[CHn].BITER.ELINKNO = DMA_TCD_BITER_ELINKNO_BITER(1)       //起始主循环次数
                         | DMA_TCD_BITER_ELINKNO_ELINK(0);  	// The minor channel-to-channel linking is disabled
  
  DMA->TCD[CHn].NBYTES.MLNO = DMA_TCD_NBYTES_MLNO_NBYTES(count);     //count  通道每次传输字节数，这里设置为BYTEs个字节。注：值为0表示传输4GB */
  
  /* 配置 DMA 传输结束后的操作 */
  DMA->TCD[CHn].SLAST     = DMA_TCD_DLASTSGA_DLASTSGA(-count);       //调整源地址的附加值,主循环结束后恢复  源地址
  DMA->TCD[CHn].DLASTSGA = DMA_TCD_DLASTSGA_DLASTSGA(-count);       //调整目的地址的附加值,主循环结束后恢复目的地址或者保持地址
  DMA->TCD[CHn].CSR       = (0
                        | DMA_TCD_CSR_BWC(0)                    //带宽控制,每读一次，eDMA 引擎停止 8 个周期（0不停止；1保留；2停止4周期；3停止8周期）
                      //  | DMA_TCD_CSR_DREQ_MASK                   //主循环结束后停止硬件请求
                      //  | DMA_TCD_CSR_INTMAJOR_MASK               //主循环结束后产生中断
                      //    |DMA_TCD_CSR_INTMAJOR(1)                  //主循环结束后产生中断
                          | DMA_TCD_CSR_START(0)                  //停止传输
                         );
  
  S32_NVIC->ICPR[0] = 1 << (CHn % 32);  /* IRQ12-DMA ch12: clr any pending IRQ*/
  S32_NVIC->ISER[0] = 1 << (CHn % 32);  /* IRQ12-DMA ch12: enable IRQ */
  S32_NVIC->IP[CHn] = 0xA;              /* IRQ12-DMA ch12: priority 10 of 0-15*/

  /* 开启中断 */
  //DMA_EN(CHn);                                    //使能通道CHn 硬件请求
  //DMA_IRQ_EN(CHn);                                //允许DMA通道传输
}

/******************************************************************************
*函  数：DMATransDataStart
*功　能：开启DMA传输
*参  数：
*				DMA_CHn   : 通道号（DMA_CH0 ~ DMA_CH15）
*				DADDR     : 目的地址
*返回值：无
*备  注：无
*******************************************************************************/
static inline void DMATransDataStart(DMA_CHn CHn, uint32_t address) 
{
    DMA->TCD[CHn].DADDR = (uint32_t)address;                 //目的地址
    DMA->ERQ |= (DMA_ERQ_ERQ0_MASK<<(CHn));                  //使能通道CHn 硬件请求
    DMA->TCD[CHn].CSR |= DMA_TCD_CSR_START(1);               //开始传输
}

char S_data[]="Hello World!";
char D_data[13*2];
uint32_t dma15_irqCounter = 0;
bool trans =false;
bool init = false;

/******************************************************************************
*函  数：Test_DMA_Mem2Mem
*功　能：测试DMA 内存到内存
*参  数：无
*返回值：无
*备  注：无
*******************************************************************************/
void Test_DMA_Mem2Mem(void)
{

    //uartInit(UART0, 115200);
    
    if(!init){
        DMA_MEM2MEM_Init(DMA_CH15, (void *)S_data,(void *)D_data, DMA_BYTE1, 13);  //初始化DMA
        init=true;
    }
    //printf("\n\r-----------DMA内存到内存测试-----------\n\r");
    //printf("\n\r内存1：%s", S_data);
    if(!trans){
        DMATransDataStart(DMA_CH15, (uint32_t)&D_data);     //开始传输
        trans=true;
    }
    //delayms(10);
    //printf("\n\r内存2：%s", D_data);

    //while(1);
}

//flexcan2
void DMA15_IRQHandler(void)
{

    dma15_irqCounter++;
    trans=false;
    S_data[0]++;
    DMA->CINT = 15; // clear DMA channel 15 interrupt flag
}





